package org.myframework.core;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author DJJ_F
 * @version 1.0
 * @date 2024/12/02
 * @description
 */
public class ClassPathXmlApplicationContext implements ApplicationContext {
    private static final Logger logger = LoggerFactory.getLogger(ClassPathXmlApplicationContext.class);
    private Map<String, Object> singletonObjects = new HashMap<>();

    public ClassPathXmlApplicationContext(String name) {
        try {
            // 获取xml文件的阅读器
            SAXReader reader = new SAXReader();
            // 获取配置文件的输入流
            InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream(name);
            // xml的文件对象
            Document read = reader.read(is);
            // 获取所有bean标签
            List<Node> nodes = read.selectNodes("//bean");
            // 遍历bean标签，完成对象的创建
            nodes.forEach(node -> {
                try {
                    // element 继承了 node, 有更多的方法，可以实现更多的功能
                    Element element = (Element) node;
                    // 获取属性的值
                    String id = element.attributeValue("id");
                    String className = element.attributeValue("class");
                    // 获取类对象
                    Class<?> cls = Class.forName(className);
                    // 获取无参构造器
                    Constructor<?> constructor = cls.getDeclaredConstructor();
                    // 获取对象
                    Object bean = constructor.newInstance();
                    logger.info("bean = " + bean);
                    // 将bean加入map集合，进行曝光
                    singletonObjects.put(id, bean);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
            // 遍历bean标签，完成属性赋值
            nodes.forEach(node -> {
                try {
                    Element element = (Element) node;
                    String id = element.attributeValue("id");
                    String className = element.attributeValue("class");
                    Class<?> cls = Class.forName(className);
                    // 获取该标签的所有子标签property
                    List<Element> properties = element.elements("property");
                    // 遍历所有标签来赋值
                    properties.forEach(property -> {
                        try {
                            // 获取属性名
                            String propertyName = property.attributeValue("name");
                            // 获取属性类型
                            Field field = cls.getDeclaredField(propertyName);
                            logger.info("属性名：" + propertyName);
                            // 拼接出set方法名
                            String setMethodName = "set" + propertyName.toUpperCase().charAt(0) + propertyName.substring(1);
                            // 获取set方法
                            Method setMethod = cls.getDeclaredMethod(setMethodName, field.getType());
                            // 获取value和ref标签，给属性赋值
                            String value = property.attributeValue("value");
                            String ref = property.attributeValue("ref");
                            if (value != null) {
                                // 如果value不为空，说明设置了简单类型的值，需要根据类型来赋值
                                Object actualValue = value;
                                // 获取字段的简单类型名，不带包名的
                                String typeSimpleName = field.getType().getSimpleName().toLowerCase();
                                switch (typeSimpleName) {
                                    case "byte":
                                        actualValue = Byte.parseByte(value);
                                        break;
                                    case "short":
                                        actualValue = Short.parseShort(value);
                                        break;
                                    case "int":
                                        actualValue = Integer.parseInt(value);
                                        break;
                                    case "long":
                                        actualValue = Long.parseLong(value);
                                        break;
                                    case "float":
                                        actualValue = Float.parseFloat(value);
                                        break;
                                    case "double":
                                        actualValue = Double.parseDouble(value);
                                        break;
                                    case "boolean":
                                        actualValue = Boolean.parseBoolean(value);
                                        break;
                                    case "char":
                                        actualValue = value.charAt(0);
                                        break;
                                    case "character":
                                        actualValue = value.charAt(0);
                                        break;
                                    case "integer":
                                        actualValue = Integer.valueOf(value);
                                        break;
                                }
                                setMethod.invoke(singletonObjects.get(id), actualValue);
                            }
                            if (ref != null) {
                                // 如果ref不为空，说明设置了非简单类型的值，并且应该也是bean。直接到缓存里取
                                setMethod.invoke(singletonObjects.get(id), singletonObjects.get(ref));
                            }
                            // 调用方法赋值, 调用缓存获取对象
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    });
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
        } catch (DocumentException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Object getBean(String name) {
        return singletonObjects.get(name);
    }
}
